/************************************************************
   Copyright 2008 Abhinav Pobbati

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
*************************************************************/

#pragma once
#include "Havok4Xna/Physics/Dynamics/HkpDynamics.h"
#include "Havok4Xna/Physics/Dynamics/Action/HkpAction.h"

#pragma unmanaged
#include <Physics/Dynamics/Constraint/hkpConstraintData.h>
#include <Physics/Dynamics/Constraint/hkpConstraintInfo.h>
#include <Physics/Dynamics/Constraint/hkpConstraintInstance.h>
#include <Physics/Dynamics/Constraint/hkpConstraintListener.h>
#include <Physics/Dynamics/Constraint/hkpConstraintOwner.h>
#include <Physics/Dynamics/Constraint/ConstraintKit/hkpConstraintConstructionKit.h>
#include <Physics/Dynamics/Constraint/Bilateral/BallAndSocket/hkpBallAndSocketConstraintData.h>
#include <Physics/Dynamics/Constraint/Chain/hkpConstraintChainData.h>
#include <Physics/Dynamics/Constraint/Chain/BallSocket/hkpBallSocketChainData.h>
#include <Physics/Dynamics/Constraint/Breakable/hkpBreakableConstraintData.h>
#include <Physics/Dynamics/Constraint/Breakable/hkpBreakableListener.h>
#include <Physics/Dynamics/Constraint/Motor/hkpConstraintMotor.h>
#include <Physics/Dynamics/Constraint/Motor/hkpLimitedForceConstraintMotor.h>
#include <Physics/Dynamics/Constraint/Motor/Callback/hkpCallbackConstraintMotor.h>
#include <Physics/Dynamics/Constraint/Contact/hkpContactImpulseLimitBreachedListener.h>
#include <Physics/Dynamics/Constraint/Contact/hkpDynamicsCpIdMgr.h>
#include <Physics/Dynamics/Constraint/ConstraintKit/hkpGenericConstraintData.h>
#include <Physics/Dynamics/Constraint/Bilateral/Hinge/hkpHingeConstraintData.h>
#include <Physics/Dynamics/Constraint/Chain/HingeLimits/hkpHingeLimitsData.h>
#include <Physics/Dynamics/Constraint/Bilateral/LimitedHinge/hkpLimitedHingeConstraintData.h>
#include <Physics/Dynamics/Constraint/Bilateral/PointToPath/hkpLinearParametricCurve.h>
#include <Physics/Dynamics/Constraint/Malleable/hkpMalleableConstraintData.h>
#include <Physics/Dynamics/Constraint/Bilateral/PointToPath/hkpPointToPathConstraintData.h>
#include <Physics/Dynamics/Constraint/Bilateral/PointToPlane/hkpPointToPlaneConstraintData.h>
#include <Physics/Dynamics/Constraint/Motor/Position/hkpPositionConstraintMotor.h>
#include <Physics/Dynamics/Constraint/Chain/Powered/hkpPoweredChainData.h>
#include <Physics/Dynamics/Constraint/Bilateral/Prismatic/hkpPrismaticConstraintData.h>
#include <Physics/Dynamics/Constraint/Pulley/hkpPulleyConstraintData.h>
#include <Physics/Dynamics/Constraint/Bilateral/Ragdoll/hkpRagdollConstraintData.h>
#include <Physics/Dynamics/Constraint/Chain/RagdollLimits/hkpRagdollLimitsData.h>
#include <Physics/Dynamics/Constraint/Bilateral/rotational/hkpRotationalConstraintData.h>
#include <Physics/Dynamics/Constraint/Contact/hkpSimpleContactConstraintData.h>
#include <Physics/Dynamics/Constraint/Motor/SpringDamper/hkpSpringDamperConstraintMotor.h>
#include <Physics/Dynamics/Constraint/Chain/StiffSpring/hkpStiffSpringChainData.h>
#include <Physics/Dynamics/Constraint/Bilateral/StiffSpring/hkpStiffSpringConstraintData.h>
#include <Physics/Dynamics/Constraint/Motor/Velocity/hkpVelocityConstraintMotor.h>
#include <Physics/Dynamics/Constraint/Bilateral/Wheel/hkpWheelConstraintData.h>
#include <Physics/Dynamics/Constraint/Chain/hkpConstraintChainInstanceAction.h>
#pragma managed

using System::Runtime::InteropServices::OutAttribute;

namespace Havok4Xna {
	namespace Physics {
		namespace Dynamics {
			ref class HkpAction;
			
			public ref class HkpConstraintInfo : public INativeReference {
			public:
				HkpConstraintInfo();
				DECLARE_PROPERTY_GETSET(int, MaxSizeOfSchema);
				DECLARE_PROPERTY_GETSET(int, SizeOfSchemas);
				DECLARE_PROPERTY_GETSET(int, NumSolverResults);
				DECLARE_PROPERTY_GETSET(int, NumSolverElemTemps);

				void Clear();
				void AddHeader();
				void Add(int schemaSize, int numSolverResults, int numSolverTempElems);
				void Add(HkpConstraintInfo ^other);
				void Sub(HkpConstraintInfo ^other);
				void Merge(HkpConstraintInfo ^other);

			internal:
				HK_CLASS_INTERNALS(HkpConstraintInfo, hkpConstraintInfo)
			};

			public ref class HkpConstraintData : public INativeReference {
			public:
				enum class ConstraintType : int {
					BallAndSocket = hkpConstraintData::CONSTRAINT_TYPE_BALLANDSOCKET,
					Hinge = hkpConstraintData::CONSTRAINT_TYPE_HINGE,
					LimitedHinge = hkpConstraintData::CONSTRAINT_TYPE_LIMITEDHINGE,
					PointToPath = hkpConstraintData::CONSTRAINT_TYPE_POINTTOPATH,
					Prismatic = hkpConstraintData::CONSTRAINT_TYPE_PRISMATIC,
					Ragdoll = hkpConstraintData::CONSTRAINT_TYPE_RAGDOLL,
					StiffSpring = hkpConstraintData::CONSTRAINT_TYPE_STIFFSPRING,
					Wheel = hkpConstraintData::CONSTRAINT_TYPE_WHEEL,
					Generic = hkpConstraintData::CONSTRAINT_TYPE_GENERIC,
					Contact = hkpConstraintData::CONSTRAINT_TYPE_CONTACT,
					Breakable = hkpConstraintData::CONSTRAINT_TYPE_BREAKABLE,
					Malleable = hkpConstraintData::CONSTRAINT_TYPE_MALLEABLE,
					PointToPlane = hkpConstraintData::CONSTRAINT_TYPE_POINTTOPLANE,
					Pulley = hkpConstraintData::CONSTRAINT_TYPE_PULLEY,
					Rotational = hkpConstraintData::CONSTRAINT_TYPE_ROTATIONAL,
					HingeLimits = hkpConstraintData::CONSTRAINT_TYPE_HINGE_LIMITS,
					RagdollLimits = hkpConstraintData::CONSTRAINT_TYPE_RAGDOLL_LIMITS,
					Custom = hkpConstraintData::CONSTRAINT_TYPE_CUSTOM,
					StiffSpringChain = hkpConstraintData::CONSTRAINT_TYPE_STIFF_SPRING_CHAIN,
					BallSocketChain = hkpConstraintData::CONSTRAINT_TYPE_BALL_SOCKET_CHAIN,
					PoweredChain = hkpConstraintData::CONSTRAINT_TYPE_POWERED_CHAIN
        };

				ref class RuntimeInfo sealed : public INativeReference {
				public:
					RuntimeInfo();
					DECLARE_PROPERTY_GETSET(int, SizeOfExternalRuntime);
					DECLARE_PROPERTY_GETSET(int, NumSolverResults);

				internal:
					HK_CLASS_INTERNALS(RuntimeInfo, hkpConstraintData::RuntimeInfo)
				};

				DECLARE_PROPERTY_GETSET(System::UInt32, UserData);
				DECLARE_PROPERTY_GET(bool, IsValid);
				DECLARE_PROPERTY_GET(int, Type);
				void GetRuntimeInfo(bool wantRuntime, [Out] RuntimeInfo ^infoOut);
				/*HkpSolverResults ^GetSolverResults(HkpConstraintRuntime ^runtime);
				void AddInstance(HkpConstraintInstance ^constraint, HkpConstraintRuntime ^runtime, int sizeOfRuntime);
				void RemoveInstance(HkpConstraintInstance ^constraint, HkpConstraintRuntime ^runtime, int sizeOfRuntime);*/

			internal:
				HK_CLASS_INTERNALS(HkpConstraintData, hkpConstraintData)
			};

			public ref class HkpConstraintChainData : public HkpConstraintData {
			internal:
				HK_DERIVED_CLASS_INTERNALS(HkpConstraintChainData, hkpConstraintChainData, HkpConstraintData)
			};

			public ref class HkpBallSocketChainData : public HkpConstraintChainData {
			public:
				ref class ConstraintInfo : public INativeReference {
				internal:
					HK_CLASS_INTERNALS(ConstraintInfo, hkpBallSocketChainData::ConstraintInfo)
				};

			internal:
				HK_DERIVED_CLASS_INTERNALS(HkpBallSocketChainData, hkpBallSocketChainData, HkpConstraintChainData)
			};

			public ref class HkpBallAndSocketConstraintData : public HkpConstraintData {
			internal:
				HK_DERIVED_CLASS_INTERNALS(HkpBallAndSocketConstraintData, hkpBallAndSocketConstraintData, HkpConstraintData)
			};

			public ref class HkpBreakableConstraintData : public HkpConstraintData {
			internal:
				HK_DERIVED_CLASS_INTERNALS(HkpBreakableConstraintData, hkpBreakableConstraintData, HkpConstraintData)
			};

			public ref class HkpBreakableConstraintEvent : public INativeReference {
			internal:
				HK_CLASS_INTERNALS(HkpBreakableConstraintEvent, hkpBreakableConstraintEvent)
			};

			public interface class HkpBreakableListener : public INativeReference {
				void ConstraintBrokenCallback(HkpBreakableConstraintEvent ^evt);
			};

			public ref class HkpConstraintMotor : public INativeReference {
			public:
				enum class MotorType : int {
					Invalid = hkpConstraintMotor::TYPE_INVALID,
					Position = hkpConstraintMotor::TYPE_POSITION,
					Velocity = hkpConstraintMotor::TYPE_VELOCITY,
					SpringDamper = hkpConstraintMotor::TYPE_SPRING_DAMPER,
					Callback = hkpConstraintMotor::TYPE_CALLBACK
				};
				DECLARE_PROPERTY_GET(MotorType, Type);

			internal:
				HK_CLASS_INTERNALS(HkpConstraintMotor, hkpConstraintMotor)
			};

			public ref class HkpLimitedForceConstraintMotor : public HkpConstraintMotor {
			internal:
				HK_DERIVED_CLASS_INTERNALS(HkpLimitedForceConstraintMotor, hkpLimitedForceConstraintMotor, HkpConstraintMotor)
			};

			public ref class HkpCallbackConstraintMotor : public HkpLimitedForceConstraintMotor {
			internal:
				HK_DERIVED_CLASS_INTERNALS(HkpCallbackConstraintMotor, hkpCallbackConstraintMotor, HkpLimitedForceConstraintMotor)
			};

			public ref class HkpConstraintInstance : public INativeReference {
			public:
				enum class ConstraintPriority : int {
					Invalid = hkpConstraintInstance::PRIORITY_INVALID,
					PSI = hkpConstraintInstance::PRIORITY_PSI,
					TOI = hkpConstraintInstance::PRIORITY_TOI,
					TOIHigher = hkpConstraintInstance::PRIORITY_TOI_HIGHER,
					TOIForced = hkpConstraintInstance::PRIORITY_TOI_FORCED
				};
				enum class InstanceType : int {
					Normal = hkpConstraintInstance::TYPE_NORMAL,
					Chain = hkpConstraintInstance::TYPE_CHAIN
				};
				enum class AddReferences : int {
					DoNotAddReferences = hkpConstraintInstance::DO_NOT_ADD_REFERENCES,
					DoAddReferences = hkpConstraintInstance::DO_ADD_REFERENCES
				};
				enum class CloningMode : int {
					InstancesOnly = hkpConstraintInstance::CLONE_INSTANCES_ONLY,
					DatasWithMotors = hkpConstraintInstance::CLONE_DATAS_WITH_MOTORS
				};

			internal:
				HK_CLASS_INTERNALS(HkpConstraintInstance, hkpConstraintInstance)
			};

			public ref class HkpConstraintChainInstance : public HkpConstraintInstance {
			internal:
				HK_DERIVED_CLASS_INTERNALS(HkpConstraintChainInstance, hkpConstraintChainInstance, HkpConstraintInstance)
			};

			public ref class HkpConstraintChainInstanceAction : public HkpAction {
			internal:
				HK_DERIVED_CLASS_INTERNALS(HkpConstraintChainInstanceAction, hkpConstraintChainInstanceAction, HkpAction)
			};

			public ref class HkpConstraintConstructionKit : public INativeReference {
			internal:
				HK_CLASS_INTERNALS(HkpConstraintConstructionKit, hkpConstraintConstructionKit)
			};

			public ref class HkpConstraintListener : public INativeReference {
			internal:
				HK_CLASS_INTERNALS(HkpConstraintListener, hkpConstraintListener)
			};

			public ref class HkpConstraintModifier : public INativeReference {
			internal:
				HK_CLASS_INTERNALS(HkpConstraintModifier, hkpConstraintModifier)
			};

			/*public ref class HkpConstraintSolverStep {
			internal:
				HK_CLASS_INTERNALS(HkpConstraintSolverStep, hkpConstraintSolverStep)
			};*/

			public ref class HkpContactImpulseLimitBreachedListener : public INativeReference {
			internal:
				HK_CLASS_INTERNALS(HkpContactImpulseLimitBreachedListener, hkpContactImpulseLimitBreachedListener)
			};

			public ref class HkpContactImpulseLimitBreachedListenerInfo : public INativeReference {
			internal:
				HK_CLASS_INTERNALS(HkpContactImpulseLimitBreachedListenerInfo, hkpContactImpulseLimitBreachedListenerInfo)
			};

			public ref class HkpDynamicsCpIdMgr : public INativeReference {
			internal:
				HK_CLASS_INTERNALS(HkpDynamicsCpIdMgr, hkpDynamicsCpIdMgr)
			};

			public ref class HkpGenericConstraintData : public HkpConstraintData {
			internal:
				HK_DERIVED_CLASS_INTERNALS(HkpGenericConstraintData, hkpGenericConstraintData, HkpConstraintData)
			};

			public ref class HkpHingeConstraintData : public HkpConstraintData {
			internal:
				HK_DERIVED_CLASS_INTERNALS(HkpHingeConstraintData, hkpHingeConstraintData, HkpConstraintData)
			};

			public ref class HkpHingeLimitsData : public HkpConstraintData {
			internal:
				HK_DERIVED_CLASS_INTERNALS(HkpHingeLimitsData, hkpHingeLimitsData, HkpConstraintData)
			};

			public ref class HkpLimitedHingeConstraintData : public HkpConstraintData {
			internal:
				HK_DERIVED_CLASS_INTERNALS(HkpLimitedHingeConstraintData, hkpLimitedHingeConstraintData, HkpConstraintData)
			};

			public ref class HkpLinearParametricCurve : public INativeReference {
			internal:
				HK_CLASS_INTERNALS(HkpLinearParametricCurve, hkpLinearParametricCurve)
			};

			public ref class HkpMalleableConstraintData : public HkpConstraintData {
			internal:
				HK_DERIVED_CLASS_INTERNALS(HkpMalleableConstraintData, hkpMalleableConstraintData, HkpConstraintData)
			};

			public ref class HkpPointToPathConstraintData : public HkpConstraintData {
			internal:
				HK_DERIVED_CLASS_INTERNALS(HkpPointToPathConstraintData, hkpPointToPathConstraintData, HkpConstraintData)
			};

			public ref class HkpPointToPlaneConstraintData : public HkpConstraintData {
			internal:
				HK_DERIVED_CLASS_INTERNALS(HkpPointToPlaneConstraintData, hkpPointToPlaneConstraintData, HkpConstraintData)
			};

			public ref class HkpPositionConstraintMotor : public HkpLimitedForceConstraintMotor {
			internal:
				HK_DERIVED_CLASS_INTERNALS(HkpPositionConstraintMotor, hkpPositionConstraintMotor, HkpLimitedForceConstraintMotor)
			};

			public ref class HkpPoweredChainData : public HkpConstraintChainData {
			internal:
				HK_DERIVED_CLASS_INTERNALS(HkpPoweredChainData, hkpPoweredChainData, HkpConstraintChainData)
			};

			public ref class HkpPrismaticConstraintData : public HkpConstraintData {
			internal:
				HK_DERIVED_CLASS_INTERNALS(HkpPrismaticConstraintData, hkpPrismaticConstraintData, HkpConstraintData)
			};

			public ref class HkpPulleyConstraintData : public HkpConstraintData {
			internal:
				HK_DERIVED_CLASS_INTERNALS(HkpPulleyConstraintData, hkpPulleyConstraintData, HkpConstraintData)
			};

			public ref class HkpRagdollConstraintData : public HkpConstraintData {
			internal:
				HK_DERIVED_CLASS_INTERNALS(HkpRagdollConstraintData, hkpRagdollConstraintData, HkpConstraintData)
			};

			public ref class HkpRagdollLimitsData : public HkpConstraintData {
			internal:
				HK_DERIVED_CLASS_INTERNALS(HkpRagdollLimitsData, hkpRagdollLimitsData, HkpConstraintData)
			};

			public ref class HkpRotationalConstraintData : public HkpConstraintData {
			internal:
				HK_DERIVED_CLASS_INTERNALS(HkpRotationalConstraintData, hkpRotationalConstraintData, HkpConstraintData)
			};

			public ref class HkpSimpleContactConstraintData : public HkpConstraintData {
			internal:
				HK_DERIVED_CLASS_INTERNALS(HkpSimpleContactConstraintData, hkpSimpleContactConstraintData, HkpConstraintData)
			};

			public ref class HkpSpringDamperConstraintMotor : public HkpLimitedForceConstraintMotor {
			internal:
				HK_DERIVED_CLASS_INTERNALS(HkpSpringDamperConstraintMotor, hkpSpringDamperConstraintMotor, HkpLimitedForceConstraintMotor)
			};

			public ref class HkpStiffSpringChainData : public HkpConstraintChainData {
			public:
				ref class ConstraintInfo : public INativeReference {
				internal:
					HK_CLASS_INTERNALS(ConstraintInfo, hkpStiffSpringChainData::ConstraintInfo)
				};

			internal:
				HK_DERIVED_CLASS_INTERNALS(HkpStiffSpringChainData, hkpStiffSpringChainData, HkpConstraintChainData)
			};

			public ref class HkpStiffSpringConstraintData : public HkpConstraintData {
			internal:
				HK_DERIVED_CLASS_INTERNALS(HkpStiffSpringConstraintData, hkpStiffSpringConstraintData, HkpConstraintData)
			};

			public ref class HkpVelocityConstraintMotor : public HkpLimitedForceConstraintMotor {
			internal:
				HK_DERIVED_CLASS_INTERNALS(HkpVelocityConstraintMotor, hkpVelocityConstraintMotor, HkpLimitedForceConstraintMotor)
			};

			public ref class HkpWheelConstraintData : public HkpConstraintData {
			internal:
				HK_DERIVED_CLASS_INTERNALS(HkpWheelConstraintData, hkpWheelConstraintData, HkpConstraintData)
			};
		}
	}
}
